package com.easybuilder.common.config.filter;


import com.alibaba.fastjson.JSONObject;
import com.easybuilder.common.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.Map;

@Slf4j
@Component
public class AuthorizationFilter implements Filter {
    private static final String[] OPEN_URL = new String[]{
            "/api/**", //对外提供接口
            "/file/**", //文件上传、访问接口
            "/login/**",   //登陆接口
            "/article/**", //文章接口
            "/comment/list/**", //评论列表接口
            "/seo/**", //seo相关接口
            "oauth/**", //oauth授权相关
            "/sys/**"

    };

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
        // 做认证
        boolean auth = doAuthorization(req);
        // 如果认证失败
        if (!auth) {
            res.setHeader("auth_code", "401");
            res.setContentType("application/json");
            JSONObject result = new JSONObject();
            result.put("status", 401);
            result.put("message", "认证失败");
            ServletUtil.writeJSON(res, result.toJSONString());
        } else {
            chain.doFilter(request, response);
        }
    }

    /** 请求结束后，清除当前请求的用户信息 */
    @Override
    public void destroy() {
        UserUtil.clearUser();
        log.info("请求结束，清除用户信息");
    }

    /** 检查是否通过认证 */
    private boolean doAuthorization(HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        // 日志处理
        doLog(request);
        String authorization = request.getHeader("Authorization");
        boolean anyMatch = Arrays.stream(OPEN_URL).anyMatch(url -> requestURI.contains(url.replace("**", "")));
        if (anyMatch) { // 如果匹配到开放路径，则不需认证
            //如果token不为空，需要解析token，设置当前登录用户信息，某些特殊情况下，虽然请求路径是开放的，但是某些功能仍然需要依赖登录用户信息；
            // 例如：文章列表功能是放开的，即使用户未登录，也可以使用该接口，但是如果需要展示当前用户对该文章的点赞操作，就需要获取到当前用户信息；
            // 如果不需要认证，但是传递了token，需要解析token，并把当前登录用户信息，保存到本地线程
            if (StringUtil.isNotEmpty(authorization)) {
                JwtUtil.checkToken(authorization, requestURI);
            }
            return true;
        } else { // 校验认证信息
            if (StringUtil.isEmpty(authorization)) {
                return false;
            }
            // 校验token是否通过校验（伪造token解析异常、token过期，将不会通过校验）
            boolean checked = JwtUtil.checkToken(authorization, requestURI);
            return checked;
        }
    }

    /** 日志处理 */
    private void doLog(HttpServletRequest request) {
        // 通过此方式才能够获取到nginx转发前，客户端的真实IP地址
        String forwardedFor = request.getHeader("x-forwarded-for");
        String remoteHost = request.getRemoteHost();
        String requestURI = request.getRequestURI();
        Map<String, String[]> parameterMap = request.getParameterMap();
        // 通过线程池进行异步处理，减少对正常请求的影响
        ThreadPoolUtil.getExecutor().execute(() -> {
            String realAddress = AddressUtils.getRealAddressByIP(forwardedFor);
            log.info("客户端地址：{}", forwardedFor);
            log.info("真实地址：{}" , realAddress);
            log.info("请求路径：{}" , requestURI);
            log.info("请求参数：{}", JSONObject.toJSONString(parameterMap));
        });
    }


}
